#include "dev_usart.h"

#ifdef STM32_USART2
// USART2初始化
void usart2_init(uint32 bound)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  
	// USART_TX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	// 复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);
   
    // USART_RX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    // USART NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	// 根据指定的参数初始化VIC寄存器
  
    // USART 初始化设置
	USART_InitStructure.USART_BaudRate = bound; // 串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1; // 一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No; // 无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
    USART_Init(USART2, &USART_InitStructure); // 初始化串口
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); // 开启串口接受中断
    USART_Cmd(USART2, ENABLE); // 使能串口
}
// USART2中断服务程序	
void USART2_IRQHandler(void)
{
    int8 res;
    
    if (USART_GetFlagStatus(USART2, USART_FLAG_PE) != RESET)
    {
        USART_ReceiveData(USART2);
        USART_ClearFlag(USART2, USART_FLAG_PE);
    }
    
    if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)
    {
        USART_ReceiveData(USART2);
        USART_ClearFlag(USART2, USART_FLAG_ORE);
    }
    
    if (USART_GetFlagStatus(USART2, USART_FLAG_FE) != RESET)
    {
        USART_ReceiveData(USART2);
        USART_ClearFlag(USART2, USART_FLAG_FE);
    }
    
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //中断产生
    {
        USART_ClearFlag(USART2, USART_FLAG_RXNE);
        USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志
        res = USART_ReceiveData(USART2);
        usart_receive_message(res);
    }
}

// USART发送1byte数据
void usart_send_byte(int8 ch)
{
    while(USART_GetFlagStatus(USART2,USART_FLAG_TC) == RESET);
    USART_SendData(USART2, ch);
}
#endif

// 串口初始化
void usart_init(uint32 bound)
{
#ifdef STM32_USART2
    usart2_init(bound);
#endif
}

// 主从机串口通信协议
int8 g_data_buffer_temp[4] = {'x', 'x', 'x', 'x'};  // 数据临时存储
int8 g_data_buffer_share[4] = {'x', 'x', 'x', 'x'}; // 数据对外共享，外部可访问此数组内容
int8 g_data_count_in_buffer = 0;    // 记录数据临时存储空间中的数据的数量
int8 g_data_loss_cnt = 0;           // 数据连续丢失的次数
int16 g_data_loss_time = 0;         // 数据连续丢失时间

typedef enum _analysis_rslt
{
    ANALYSIS_FAIL = 0,
    ANALYSIS_SUCCESS,
} analysis_rslt_e;
analysis_rslt_e com_rslt = ANALYSIS_FAIL; // 用于校验数据的首尾字节

void clear_data_bufer_temp(void)
{
    g_data_buffer_temp[0] = 'x';
    g_data_buffer_temp[1] = 'x';
    g_data_buffer_temp[2] = 'x';
    g_data_buffer_temp[3] = 'x';
    g_data_count_in_buffer = 0;
}
void clear_data_bufer_share(void)
{
    g_data_buffer_share[0] = 'x';
    g_data_buffer_share[1] = 'x';
    g_data_buffer_share[2] = 'x';
    g_data_buffer_share[3] = 'x';
}

void load_data_to_buffer(int8 data)
{
    int8 i = 0;
    for (i = 0; i < 4; i++)
    {
        if (g_data_buffer_temp[i] == 'x')
        {
            if (i == 0 && data != '!')
            {
                ++g_data_loss_cnt;
                if (g_data_loss_cnt > 3)
                {
                    g_data_loss_cnt = 0;
                    clear_data_bufer_share();
                }
                return;
            }
            g_data_count_in_buffer = i + 1;
            g_data_buffer_temp[i] = data;
            break;
        }
    }
}

// 校验接收的数据是否正确
analysis_rslt_e analysis_message(void)
{
    analysis_rslt_e rlst = ANALYSIS_FAIL;
    if ('!' == g_data_buffer_temp[0] && '@' == g_data_buffer_temp[3])
    {
        rlst = ANALYSIS_SUCCESS;
    }
    else
    {
        rlst = ANALYSIS_FAIL;
    }
    clear_data_bufer_temp();
    return rlst;
}

// 串口接收数据函数
void usart_receive_message(int8 data)
{
    analysis_rslt_e rlst = ANALYSIS_FAIL;
    g_data_loss_time = 0;
    load_data_to_buffer(data); 
    if (4 == g_data_count_in_buffer)
    {
        g_data_count_in_buffer = 0;
        g_data_buffer_share[0] = g_data_buffer_temp[0];
        g_data_buffer_share[1] = g_data_buffer_temp[1];
        g_data_buffer_share[2] = g_data_buffer_temp[2];
        g_data_buffer_share[3] = g_data_buffer_temp[3];
        rlst = analysis_message();
        if (rlst == ANALYSIS_FAIL)
        {
            g_data_buffer_share[0] = g_data_buffer_temp[0];
            g_data_buffer_share[1] = g_data_buffer_temp[1];
            g_data_buffer_share[2] = g_data_buffer_temp[2];
            g_data_buffer_share[3] = g_data_buffer_temp[3];
        }
    }
}

// 串口发送数据函数
// 一次发送四个字节，其中首位字节用于数据校验
void usart_send_message(int8 cmd, int8 data)
{
    usart_send_byte('!');
    usart_send_byte(cmd);
    usart_send_byte(data);
    usart_send_byte('@');
}

// 数据丢失计时，5s丢失则清空data_buffer
// 此函数用于定时器中断中
// frequency：定时器中断频率
// sec: 几秒清空buffer
void check_data_loss_time(int16 frequency, int16 sec)
{
    g_data_loss_time++;
    if (g_data_loss_time > frequency * sec)
    {
        clear_data_bufer_temp();
        clear_data_bufer_share();
    }
}
